package com.rz.htk.product.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rz.core.exception.GlobalException;
import com.rz.core.kit.RedisKit;
import com.rz.htk.config.RedisKeyConfig;
import com.rz.htk.destination.entity.Destination;
import com.rz.htk.destination.service.IDestinationService;
import com.rz.htk.dubbo.service.DictDataService;
import com.rz.htk.dubbo.service.SysCountryService;
import com.rz.htk.dubbo.service.SysZoneService;
import com.rz.htk.order.entity.Order;
import com.rz.htk.product.entity.Product;
import com.rz.htk.product.entity.ProductDiscount;
import com.rz.htk.product.entity.ProductPrice;
import com.rz.htk.product.entity.vo.PrdDeleteParam;
import com.rz.htk.product.entity.vo.PrdPriceParam;
import com.rz.htk.product.mapper.ProductPriceMapper;
import com.rz.htk.product.service.IProductDiscountService;
import com.rz.htk.product.service.IProductPriceService;
import com.rz.htk.product.service.IProductService;
import consumer.model.Country;
import consumer.model.SysDictData;
import consumer.model.Zone;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName ProductPriceServiceImpl
 * @Description 产品资费信息
 * @Author maweiyue
 * @Date 2019/3/26 20:40
 */
@Service
public class ProductPriceServiceImpl extends ServiceImpl<ProductPriceMapper, ProductPrice> implements IProductPriceService {

    @Resource
    private IProductService productService;
    @Resource
    private DictDataService dictDataService;
    @Resource
    private RedisKit redisKit;
    @Resource
    private SysCountryService sysCountryService;
    @Resource
    private IProductDiscountService productDiscountService;
    @Resource
    private SysZoneService sysZoneService;
    @Resource
    private IDestinationService destinationService;

    @Override
    public IPage<ProductPrice> getPage(ProductPrice product) {
        QueryWrapper<ProductPrice> wrapper = new QueryWrapper();
        if(!StringUtils.isEmpty(product.getPrdCode())){
            wrapper.eq("prd_code",product.getPrdCode());
        }
        wrapper.eq("del_flag", 0);
        Page<ProductPrice> page = new Page<>(product.getPageNo(), product.getPageSize());
        IPage<ProductPrice> priceIPage = page(page, wrapper);
        this.buildResult(priceIPage.getRecords());
        return priceIPage;
    }

    private void buildResult(List<ProductPrice> list){
        if(list.isEmpty()){
            return;
        }
        List<String> prdCodeList = new ArrayList<>();
        List<String> countryCodeList = new ArrayList<>();
        list.forEach(productPrice -> {
            prdCodeList.add(productPrice.getPrdCode());
            countryCodeList.add(productPrice.getCountryCode());
        });
        List<Product> prdList = productService.listProductByCodes(prdCodeList);
        List<Country> countryList = this.sysCountryService.listCountryByCode(countryCodeList);
        list.forEach(productPrice -> {
            SysDictData dictData = dictDataService.getByCode("send_type_"+productPrice.getPackageType());
            if(dictData!=null){
                productPrice.setPackageName(dictData.getDictdataName());
            }
            prdList.forEach(product -> {
                if (productPrice.getPrdCode().equals(product.getPrdCode())) {
                    productPrice.setPrdName(product.getPrdName());
                }
            });
            countryList.forEach(country -> {
                if (country.getCode().equals(productPrice.getCountryCode())) {
                    productPrice.setCountryName(country.getcName());
                }
            });
        });
    }

    @Transactional
    public boolean saveProductPrice(ProductPrice price){
        if (price.getId() == null) {
            List<ProductPrice> temp = listProductPriceByDestination(price.getPrdCode(), price.getDestination());
            if (CollectionUtils.isNotEmpty(temp)) {
                ProductPrice old = temp.get(0);
                if (old.getMinWeight() == price.getMinWeight() && old.getMaxWeight() == price.getMaxWeight()) {
                    throw new GlobalException("产品【" + price.getPrdCode() + "】的路向【" + price.getDestination() + "】资费信息已存在！");
                }
            }
            price.setCrteTime(LocalDateTime.now());
            price.setDelFlag(0);
        } else {
            List<ProductPrice> oldProductList = listProductPriceByDestination(price.getPrdCode(), price.getDestination());
            if (CollectionUtils.isNotEmpty(oldProductList) && !price.getId().equals(oldProductList.get(0).getId())) {
                ProductPrice old = oldProductList.get(0);
                if (old.getMinWeight() == price.getMinWeight() && old.getMaxWeight() == price.getMaxWeight()) {
                    throw new GlobalException("产品【" + price.getPrdCode() + "】的路向【" + price.getDestination() + "】资费信息已存在！");
                }
            }
        }
        // 根据“挂号费”是否大于0去判断是平邮还是挂号
        if (price.getCertificationFee() > 0) {
            price.setExpressType("2");
        } else {
            price.setExpressType("1");
        }
        boolean isOk = this.saveOrUpdate(price);
        if (!isOk) {
            throw new GlobalException("产品信息保存失败！");
        } else {
            Product product = this.productService.getProductByCode(price.getPrdCode());
            if (product != null) {
                redisKit.putHash(RedisKeyConfig.PRICE, this.getProductPriceName(product, price), price);
            }
        }
        return true;
    }

    /**
     * 获取路向名称
     * @param product  产品实体bean
     * @param productPrice  产品资费信息bean
     * @return
     */
    public String getProductPriceName (Product product, ProductPrice productPrice) {
        StringBuffer sb = new StringBuffer();
        sb.append("海淘客-");
        if (product != null) {
            sb.append(product.getPrdName());
        }
        sb.append("-");
        sb.append(productPrice.getDestination());
        if ("2".equals(productPrice.getExpressType())) {
            sb.append("(挂号)");
        }
        if (productPrice.getMinWeight() != 0 || productPrice.getMaxWeight() != 0) {
            sb.append(productPrice.getMinWeight() + "-" + productPrice.getMaxWeight());
            SysDictData dictData = dictDataService.getByCode("unit_" + product.getUnit());
            if(dictData!=null){
                sb.append(dictData.getDictdataName());
            }
        }

        return sb.toString();
    }

    @Override
    @Transactional
    public boolean batchDelete(PrdDeleteParam prdDeleteParam){
        prdDeleteParam.getIds().forEach(id -> {
            ProductPrice price = this.getById(id);
            if (price != null) {
                price.setDelFlag(1);
                boolean isOk = this.saveOrUpdate(price);
                if (!isOk) {
                    throw new GlobalException("产品【" + price.getPrdCode() + "】的路向【" + price.getDestination() + "】资费信息删除失败！");
                } else {
                    Product product = this.productService.getProductByCode(price.getPrdCode());
                    if (product != null) {
                        redisKit.deleteHash(RedisKeyConfig.PRICE, this.getProductPriceName(product, price));
                    }
                }
            } else {
                throw new GlobalException("产品资费信息不存在，删除失败！");
            }
        });
        return true;
    }

    /**
     * 根据“路向”获取指定产品的资费信息
     * @param prdCode      产品编号
     * @param destination  路向
     * @return
     */
    @Override
    public List<ProductPrice> listProductPriceByDestination(String prdCode, String destination){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("prd_code", prdCode);
        queryWrapper.eq("destination", destination);
        queryWrapper.eq("del_flag", 0);
        return list(queryWrapper);
    }

    /**
     * 根据“国家”“产品”获取资费信息
     * @param prdCode      产品编号
     * @param country  国家2字符简码
     * @return
     */
    @Override
    public List<ProductPrice> getDestination(String prdCode, String country){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("prd_code", prdCode);
        queryWrapper.eq("country_code", country);
        queryWrapper.eq("del_flag", 0);
        return list(queryWrapper);
    }

    /**
     * 根据产品编号获取产品资费信息列表
     * @param prdCode 产品编号
     * @return
     */
    @Override
    public List<ProductPrice> listProductPriceByPrdcode(String prdCode){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", 0);
        queryWrapper.eq("prd_code", prdCode);
        queryWrapper.orderByAsc("express_type","id");
        return list(queryWrapper);
    }

    /**
     * 根据国家代码获取产品资费列表
     * @param code
     * @return
     */
    @Override
    public List<ProductPrice> listProductPriceByCountry(String code){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", 0);
        queryWrapper.eq("country_code", code);
        return list(queryWrapper);
    }

    /**
     * 根据国家代码和包裹类型获取资费信息列表
     * @param countryCode 国家代码
     * @param packageType 包裹类型
     * @return
     */
    public List<ProductPrice> listProductPriceByCountryAndPackageType(String countryCode, String packageType){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", 0);
        queryWrapper.eq("country_code", countryCode);
        queryWrapper.eq("package_type", packageType);
        return list(queryWrapper);
    }

    /**
     * 根据产品编码、目的地国家代码、包裹重量获取产品资费列表
     * @param prdCode
     * @param contry
     * @param weight
     * @return
     */
    public List<ProductPrice> listProductPrice(String prdCode, String contry, Double weight){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", 0);
        queryWrapper.eq("country_code", contry);
        queryWrapper.eq("prd_code", prdCode);
        queryWrapper.lt("min_Weight", weight);
        queryWrapper.ge("max_Weight", weight);
        List<ProductPrice> list = list(queryWrapper);
        return list;
    }

    /**
     * 根据产品编码、目的地国家代码、包裹重量、邮政分区获取产品资费列表
     * @param prdCode
     * @param contry
     * @param weight
     * @param zone   邮政分区号（例如美国分为1-9区）
     * @return
     */
    public List<ProductPrice> listProductPrice(String prdCode, String contry, Double weight, String zone){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", 0);
        queryWrapper.eq("country_code", contry);
        queryWrapper.eq("prd_code", prdCode);
        queryWrapper.eq("zone", zone);
        queryWrapper.lt("min_Weight", weight);
        queryWrapper.ge("max_Weight", weight);
        List<ProductPrice> list = list(queryWrapper);
        return list;
    }
    /**
     * 根据产品编码、目的地国家代码、包裹体积、邮政分区获取产品资费列表
     * @param prdCode
     * @param contry
     * @param volume
     * @param zone   邮政分区号（例如美国分为1-9区）
     * @return
     */
    public List<ProductPrice> listProductPriceByVolume(String prdCode, String contry, Double volume, String zone){
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq("del_flag", 0);
        queryWrapper.eq("country_code", contry);
        queryWrapper.eq("prd_code", prdCode);
        queryWrapper.eq("zone", zone);
        queryWrapper.lt("min_size", volume);
        queryWrapper.ge("max_size", volume);
        List<ProductPrice> list = list(queryWrapper);
        return list;
    }

    /**
     * 根据订单信息获取最优资费标准
     * @param order 订单信息
     * @return
     */
    public ProductPrice getBestProductPrice(Order order){
        List<ProductPrice> list = null;
        if ("HTK_P0022".equals(order.getPrdCode()) || "HTK_P0023".equals(order.getPrdCode())) {
            // 这两个产品“PriorityMail”和“First-Class”是USPS发往美国国内的，美国国内邮政有分区，不同分区资费标准不一样
            Zone zone = this.selectBestZone(order);
            if (zone != null) {
                if ("HTK_P0022".equals(order.getPrdCode())
                        && (StringUtils.isNotEmpty(order.getLongs()) && !"0".equals(order.getLongs()))
                        && (StringUtils.isNotEmpty(order.getWidth()) && !"0".equals(order.getWidth()))
                        && (StringUtils.isNotEmpty(order.getHigh()) && !"0".equals(order.getHigh()))) {
                    // HTK_P0022产品如果订单有长宽高，就按照体积计费，否则按照重量计费
                    double inchLongs = Double.parseDouble(order.getLongs()) * 0.3937008;
                    double inchWidth = Double.parseDouble(order.getWidth()) * 0.3937008;
                    double inchHigh = Double.parseDouble(order.getHigh()) * 0.3937008;
                    Double volume = inchLongs * inchWidth * inchHigh / 1728;
                    list = this.listProductPriceByVolume(order.getPrdCode(), order.getDestination(), volume, zone.getZone());
                } else {
                    list = this.listProductPrice(order.getPrdCode(), order.getDestination(), order.getRoughWeight(), zone.getZone());
                }
            } else {
                throw new GlobalException("收件人邮编【"+order.getRecipientsPostcode()+"】找不到邮政分区，但产品【\"+order.getPrdCode()+\"】强制要求邮政分区信息");
            }
        } else {
            list = this.listProductPrice(order.getPrdCode(), order.getDestination(), order.getRoughWeight());
        }
        if (list != null && list.size() == 1) {
            return list.get(0);
        }
        return selectBestProductPrice(order, list);
    }

    public ProductPrice selectBestProductPrice(Order order, List<ProductPrice> list){
        if (list != null && list.size() > 1) {
            ProductPrice best  = null;
            Double bestPrice = null;
            for (ProductPrice productPrice : list) {
                ProductDiscount discount = this.productDiscountService.getProductDiscount(order.getCrteMngId(), productPrice.getId());
                double price = quote(productPrice, discount, order.getRoughWeight(), 0, 0, 0);
                if (bestPrice == null) {
                    bestPrice = price;
                    best = productPrice;
                } else if (price < bestPrice) {
                    bestPrice = price;
                    best = productPrice;
                }
            }
            return best;
        }
        return null;
    }

    /**
     * 查询一个订单发到哪个中转“仓库”最优。比如发往美国的快递，美国有两个中转仓库，就需要根据快递的目的地邮编查询从哪个仓库走更省钱
     * @param order 订单信息
     * @return Zone(Zone中包含中转仓库的邮编，由此可获得中转仓库信息)
     */
    public Zone selectBestZone(Order order){
        // 首先获取目的地的中转仓库信息
        // 暂时写死美国的两个仓库邮编信息为113、900（跟数据库sys_zone表中的zip字段对应）
        List<Destination> zipList = destinationService.listByCountry(order.getDestination());
        int minZone = Integer.MAX_VALUE;
        Zone result = null;
        Destination bestDestination = null;
        for (Destination destination : zipList) {
            // 获取目的港邮编前三位
            String zip = destination.getZip().substring(0, 3);
            Zone zone = this.sysZoneService.getByContryAndZip(order.getDestination(), zip, order.getRecipientsPostcode());
            if (zone != null && Integer.parseInt(zone.getZone()) < minZone) {
                result = zone;
                minZone = Integer.parseInt(zone.getZone());
            }
        }
        return result;
    }

    /**
     * 报价
     * @param order 订单信息
     * @return
     */
    public double quote(Order order) {
        ProductPrice p = this.getById(order.getTransportation());
        double weight = 0;
        if (p != null) {
            if(order.getRoughWeight()!=null&&order.getRoughWeight()>0){
                weight = order.getRoughWeight();
            }else {
                weight = order.getWeight();
            }
            double longs = 0;double width = 0;double high = 0;double volume;
            if(StringUtils.isNotEmpty(order.getLongs())){
                longs = Double.parseDouble(order.getLongs());
            }
            if(StringUtils.isNotEmpty(order.getWidth())){
                width = Double.parseDouble(order.getWidth());
            }
            if(StringUtils.isNotEmpty(order.getHigh())){
                high = Double.parseDouble(order.getHigh());
            }
            ProductDiscount discount = this.productDiscountService.getProductDiscount(order.getCrteMngId(), p.getId());
            return this.quote(p, discount, weight, longs, width, high);
        } else {
            throw new GlobalException("产品资费信息不存在，无法计算总价。");
        }
    }

    /**
     * 报价
     * @param p 产品资费标准
     * @param weight 重量
     * @param longs 长
     * @param width 宽
     * @param high 高
     * @return
     */
    public double quote(ProductPrice p, ProductDiscount productDiscount, double weight, double longs, double width, double high) {
        if ("1".equals(p.getPriceType())) {
            // 按重量计费
            return quotedByWeight(p, productDiscount, weight);
        } else if ("2".equals(p.getPriceType())) {
            // 按体积计费
            return quotedByVolume(p, productDiscount, longs, width, high);
        } else {
            // 将体积换算成重量，然后根据换算重量和实际重量中较大的一个计费
            double volume = longs * width * high / p.getRatio();
            weight = weight > volume ? weight : volume;

            return quotedByWeight(p, productDiscount, weight);
        }
    }

    /**
     * 根据重量计算价格
     * @param p 资费信息
     * @param productDiscount 折扣
     * @param weight 重量
     * @return
     */
    public double quotedByWeight(ProductPrice p, ProductDiscount productDiscount, double weight) {
        double price;
        double certificationFee = p.getCertificationFee();
        double coverCharge = p.getCoverCharge();
        double startingPrice = p.getStartingPrice();
        double ratePrice = p.getRatePrice();
        double tax = 0, abnormal = 0, changeOrder = 0;
        double discount = 1;
        if (productDiscount != null) {
            if ("1".equals(productDiscount.getType())) {
                // 总价折扣，折扣率使用折扣表中的折扣率
                discount = productDiscount.getDiscount();
            } else if ("2".equals(productDiscount.getType())) {
                // 如果是单项计费，则首重价格和续重价格采用折扣表中的价格
                startingPrice = productDiscount.getPrice();
                ratePrice = productDiscount.getDisRatePrice();
                tax = productDiscount.getTax();
                abnormal = productDiscount.getAbnormal();
                changeOrder = productDiscount.getChangeOrder();
            }
        }
        if(weight <= p.getStartingWeight()){
            price = certificationFee + coverCharge + startingPrice + tax + abnormal + changeOrder;
        }else{
            price = Math.ceil((weight - p.getStartingWeight()) / p.getRate()) * ratePrice
                    + certificationFee + coverCharge + startingPrice + tax + abnormal + changeOrder;
        }
        // 汇率转换
        price = this.exchangeRatePrice(p, price);

        price = price * discount;
        BigDecimal b = new BigDecimal(price);
        return  b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 汇率转换
     * @param p  产品资费信息
     * @param price 价格
     * @return 汇率转换后的价格
     */
    private double exchangeRatePrice(ProductPrice p, double price){
        // 判断货币单位
        if ("USD".equals(p.getCurrency())) {
            // 美元，需要换算成人民币
            Object exchangeRateObj = redisKit.getValue(RedisKeyConfig.getExchangeRateKey(RedisKeyConfig.USD_CNY));
            if (exchangeRateObj == null) {
                throw new GlobalException("系统未设置美元/人民币汇率");
            }
            price = price * Double.parseDouble(exchangeRateObj.toString());
        }
        return price;
    }

    /**
     * 根据体积计费
     * @param p 产品资费标准
     * @param productDiscount 折扣
     * @param longs 长
     * @param width 宽
     * @param high 高
     * @return
     */
    public double quotedByVolume(ProductPrice p, ProductDiscount productDiscount, double longs, double width, double high) {
        double price;
        double volume = longs * width * high / p.getRatio();
        double certificationFee = p.getCertificationFee();
        double coverCharge = p.getCoverCharge();
        double startingSizePrice = p.getStartingSizePrice();
        double rateSizePrice = p.getRateSizePrice();
        double tax = 0, abnormal = 0, changeOrder = 0;
        double discount = 1;
        if (productDiscount != null) {
            if ("1".equals(productDiscount.getType())) {
                // 总价折扣，折扣率使用折扣表中的折扣率
                discount = productDiscount.getDiscount();
            } else if ("2".equals(productDiscount.getType())) {
                // 如果是单项计费，则首重价格和续重价格采用折扣表中的价格
                startingSizePrice = productDiscount.getPrice();
                rateSizePrice = productDiscount.getDisRatePrice();
                tax = productDiscount.getTax();
                abnormal = productDiscount.getAbnormal();
                changeOrder = productDiscount.getChangeOrder();
            }
        }
        if(volume <= p.getStartingSize()){
            price = certificationFee + coverCharge + startingSizePrice + tax + abnormal + changeOrder;
        }else{
            price = Math.ceil((volume - p.getStartingSize()) / p.getRateSize()) * rateSizePrice
                    + certificationFee + coverCharge + startingSizePrice
                    + tax + abnormal + changeOrder;
        }
        // 汇率转换
        price = this.exchangeRatePrice(p, price);

        price = price * discount;
        BigDecimal b = new BigDecimal(price);
        return  b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 描述报价的过程
     * @param p 资费信息
     * @param productDiscount 折扣
     * @param weight 重量
     * @param longs 长
     * @param width 宽
     * @param high 高
     * @return 报价过程描述
     */
    public String describeQuote(ProductPrice p, ProductDiscount productDiscount, double weight, double longs, double width, double high) {
        StringBuffer str = new StringBuffer();
        if (p.getCertificationFee() > 0) {
            // 有挂号费
            str.append(p.getCertificationFee() + "(挂号费)");
        }
        if (p.getCoverCharge() > 0) {
            // 每件处理费
            if (StringUtils.isNotEmpty(str.toString())) {
                str.append(" + ");
            }
            str.append(p.getCoverCharge() + "(每件处理费)");
        }
        if (StringUtils.isNotEmpty(str.toString())) {
            str.append(" + ");
        }
        if ("1".equals(p.getPriceType())) {
            // 按重量计费
            str.append(this.describeQuoteByWeight(p, productDiscount, weight));
        } else if ("2".equals(p.getPriceType())) {
            // 按体积计费
            str.append(this.describeQuoteByVolume(p, productDiscount, longs, width, high));
        } else {
            double volume = longs * width * high / p.getRatio();
            weight = weight > volume ? weight : volume;
            str.append(this.describeQuoteByWeight(p, productDiscount, weight));
        }
        return str.toString();
    }

    /**
     * 描述“根据重量计价”的报价过程
     * @param p 资费信息
     * @param productDiscount 折扣
     * @param weight 重量
     * @return
     */
    public String describeQuoteByWeight(ProductPrice p, ProductDiscount productDiscount, double weight) {
        StringBuffer str = new StringBuffer();
        // 首重
        str.append(p.getStartingPrice() + "(首重" + p.getStartingWeight() + "克)");
        if(weight > p.getStartingWeight()){
            str.append(" + ");
            double excessWeight = weight - p.getStartingWeight();
            // 比如续重50克x元，不足50克的按照50克计算
            excessWeight = Math.ceil(excessWeight / p.getRate());
            double excessPrice = excessWeight * p.getRatePrice();
            str.append(excessPrice + "(续重"+p.getRatePrice()+"/"+p.getRate()+":"+p.getRatePrice()+"*"+excessWeight+")");
        }
        return str.toString();
    }

    /**
     * 描述“根据体积计价”的报价过程
     * @param p 资费信息
     * @param productDiscount 折扣
     * @param longs 长
     * @param width 宽
     * @param high 高
     * @return
     */
    public String describeQuoteByVolume(ProductPrice p, ProductDiscount productDiscount, double longs, double width, double high) {
        StringBuffer str = new StringBuffer();
        // 首重
        str.append(p.getStartingPrice() + "(首重" + p.getStartingWeight() + "克)");
        double volume = longs * width * high;
        if(volume > p.getStartingSize()){
            str.append(" + ");
            double excessSize = volume - p.getStartingSize();
            // 比如续重50克x元，不足50克的按照50克计算
            excessSize = Math.ceil(excessSize / p.getRateSize());
            double excessPrice = excessSize * p.getRateSizePrice();
            str.append(excessPrice + "(续重" + p.getRateSizePrice() + "/"
                    + p.getRateSize() + ":" + p.getRateSizePrice() + "*" + excessSize + ")");
        }
        return str.toString();
    }

    /**
     * 报价
     * @param param 报价查询条件
     * @return
     */
    public JSONArray quote(PrdPriceParam param){
        List<Country> listCountry = this.sysCountryService.listCountryByName(param.getDestination());
        JSONArray array = new JSONArray();
        for(Country country : listCountry) {
            List<ProductPrice> priceList = this.listProductPriceByCountryAndPackageType(country.getCode(), param.getPackageType());
            for (ProductPrice price : priceList){
                if (!isAppliToProductPrice(price, param.getWeight(), param.getDepth(), param.getWidth(), param.getHigh())) {
                    continue;
                }
                Product prd = productService.getProductByCode(price.getPrdCode());
                if (prd != null) {
                    ProductDiscount discount = this.productDiscountService.getProductDiscount(param.getCrteMngId(), price.getId());
                    JSONObject obj = new JSONObject();
                    obj.put("name", prd.getPrdName());
                    obj.put("priceType", price.getPriceType());
                    obj.put("country", country.getcName());
                    obj.put("destination", price.getDestination());
                    obj.put("price", this.quote(price, discount, param.getWeight(), param.getDepth(), param.getWidth(), param.getHigh()));
                    obj.put("remark", this.describeQuote(price, discount, param.getWeight(), param.getDepth(), param.getWidth(), param.getHigh()));
                    obj.put("priceType", price.getPriceType());
                    array.add(obj);
                }
            }
        }
        return array;
    }

    /**
     * 判断重量/体积是否适合本资费标准
     * @param p
     * @param weight
     * @param longs
     * @param width
     * @param high
     * @return
     */
    public boolean isAppliToProductPrice(ProductPrice p, double weight, double longs, double width, double high){
        if ("1".equals(p.getPriceType())) {
            // 重量计价
            if (weight >= p.getMinWeight() && weight <= p.getMaxWeight()) {
                return true;
            }
        } else if ("2".equals(p.getPriceType())) {
            // 体积计价
            double volume = longs * width * high;
            if (volume >= p.getMinSize() && volume <= p.getMaxSize()) {
                return true;
            }
        }

        return false;
    }
}
